/*jslint bitwise: true, eqeqeq: true, immed: true, newcap: true, nomen: true,
  onevar: true, plusplus: true, regexp: true, strict: true, undef: true,
  white: true, indent: 4 */
"use strict";
(function () {
    var init, container, loadConfiguration, configuration, json, chooseFiles,
            getDefaultConfiguration, applyLoadedConfiguration, loadFiles,
            directoryAutodetection, files, loadedFiles, getXMLHttpRequest,
            importFields, checkLoadingProgress, initWebLayout, loaded;

    container = {};
    importFields = ['XMLHttpRequest', 'XPathResult', 'ActiveXObject'];
    loaded = false;

    init = function () {
        var i;
        if (loaded) {
            return;
        }
        loaded = true;
        for (i in this) {
            if (this[i] !== undefined) {
                container[i] = this[i];
            }
        }
        for (i = importFields.length - 1; i >= 0; i -= 1) {
            container[importFields[i]] = this[importFields[i]];
        }
        container.evaluator = function (code) {
            return eval(code);
        };
        loadConfiguration();
        chooseFiles();
        if (files.length === 0) {
            initWebLayout();
        } else {
            loadFiles();
        }
    };

    initWebLayout = function () {
        var webLayout, i, area, j, modules;
        for (i = configuration.areas.length - 1; i >= 0; i -= 1) {
            area = container.document.evaluate(configuration.areas[i],
                    container.document, null, container.XPathResult.ANY_TYPE,
                    null).iterateNext();
            webLayout = new container.WebLayout2(area);
            if (configuration.moduleLoader) {
                webLayout.addModule(new container.ModuleLoader());
            }
            modules = configuration.modules;
            for (j = modules.length - 1; j >= 0; j -= 1) {
                webLayout.addModule(new container[modules[j]]());
            }
            if (configuration.configType !== null) {
                webLayout.addModule(new container[configuration.configType +
                        'Config']());
            }
        }
    };

    checkLoadingProgress = function () {
        var i;
        for (i = loadedFiles.length - 1; i >= 0; i -= 1) {
            if (!loadedFiles[i]) {
                return;
            }
        }
        for (i = loadedFiles.length - 1; i >= 0; i -= 1) {
            container.evaluator(loadedFiles[i]);
            if (files[i] === 'xpath.js') {
                container.XPathResult = this.XPathResult;
            }
        }
        initWebLayout();
    };

    loadFiles = function () {
        var i, xmlHttpRequest;
        loadedFiles = [];
        for (i = files.length - 1; i >= 0; i -= 1) {
            loadedFiles[i] = false;
            xmlHttpRequest = getXMLHttpRequest(i);
            xmlHttpRequest.open('GET', (configuration.directory === '' ? '' :
                    configuration.directory + '/') + files[i], true);
            xmlHttpRequest.send(null);
        }
    };

    getXMLHttpRequest = function (index) {
        var xmlHttpRequest;
        xmlHttpRequest = container.XMLHttpRequest !== undefined ?
                new container.XMLHttpRequest() :
                new container.ActiveXObject("Microsoft.XMLHTTP");
        xmlHttpRequest.onreadystatechange = function () {
            if ((xmlHttpRequest.readyState !== 4) ||
                    (xmlHttpRequest.status !== 200)) {
                return;
            }
            loadedFiles[index] = xmlHttpRequest.responseText;
            checkLoadingProgress();
        };
        return xmlHttpRequest;
    };

    chooseFiles = function () {
        var i;
        if (configuration.compressed) {
            files = ['compressed.js'];
        } else {
            files = (container.WebLayout2 instanceof Function) ? [] :
                    ['weblayout2.js'];
            if (configuration.ajaxLib &&
                    !(container.AJAXlib2 instanceof Function)) {
                files.push('ajaxlib2.1.js');
            }
            if (configuration.moduleLoader &&
                    !(container.ModuleLoader instanceof Function)) {
                files.push('moduleloader.js');
            }
            if ((configuration.configType !== null) && !(container[
                    configuration.configType + 'Config'] instanceof
                    Function)) {
                files.push(configuration.configType.toLowerCase() +
                        'config.js');
            }
            for (i = configuration.modules.length - 1; i >= 0; i -= 1) {
                if (!(container[configuration.modules[i]] instanceof
                        Function)) {
                    files.push(configuration.modules[i].toLowerCase() + '.js');
                }
            }
        }
        if (configuration.css && !(container.document.querySelectorAll
                instanceof Function)) {
            files.push('selector.js');
        }
        if (configuration.json && !(container.JSON instanceof Object)) {
            files.push('json2.js');
        }
        if (!(container.document.evaluate instanceof Function)) {
            files.push('xpath.js');
        }
    };

    loadConfiguration = function () {
        var node, newConfiguration = null;
        node = container.document.body.firstChild;
        while (node !== null) {
            if (node.nodeType === 8) {
                if (node.nodeValue.substring(0, 11) === 'InitLoader:') {
                    newConfiguration = json(node.nodeValue.substring(11));
                    break;
                }
            }
            node = node.nextSibling;
        }
        configuration = getDefaultConfiguration();
        newConfiguration = newConfiguration === null ? {} : newConfiguration;
        applyLoadedConfiguration(configuration, newConfiguration);
        directoryAutodetection();
        if (typeof configuration.areas === 'string') {
            configuration.areas = [configuration.areas];
        }
    };

    directoryAutodetection = function () {
        var scripts, i;
        if (configuration.directory !== null) {
            return;
        }
        scripts = container.document.getElementsByTagName('script');
        for (i = scripts.length - 1; i >= 0; i -= 1) {
            if (scripts[i].src.toLowerCase().indexOf('initloader.js') > -1) {
                configuration.directory =
                        scripts[i].src.replace(/\/initloader\.js$/i, '');
            }
        }
    };

    applyLoadedConfiguration = function (original, changes) {
        var i;
        for (i in changes) {
            if (changes.hasOwnProperty(i) && (original[i] !== undefined)) {
                original[i] = changes[i];
            }
        }
    };

    getDefaultConfiguration = function () {
        var configuration = {
            directory: null,
            configType: "JSON",
            ajaxLib: true,
            css: false,
            json: true,
            moduleLoader: false,
            compressed: false,
            modules: [],
            areas: "//body"
        };
        return configuration;
    };

    json = function (jsonString) {
        if ((container.JSON instanceof Object) &&
                (container.JSON.parse instanceof Function)) {
            return container.JSON.parse(jsonString);
        }
        try {
            // Source: http://www.ietf.org/rfc/rfc4627.txt?number=4627
            return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                    jsonString.replace(/"(\\([^a]|a)|[^"\\])*"/g, ''))) &&
                    container.evaluator('(' + jsonString + ')');
        } catch (e) {}
        return false;
    };

    // this has been inspired by jQuery1.3.2 - jquery.com
    if (this.addEventListener instanceof Function) {
        this.addEventListener('DOMContentLoaded', init, false);
        this.addEventListener('load', init, false);
    } else {
        this.document.attachEvent('onreadystatechange', function () {
            if (this.document.readyState === 'complete') {
                init();
            }
        });
        this.attachEvent('onload', init);
    }
}());